/**
 * Stok3d - getting you stoked on Flash Player native 3D
 * Copyright (C) 2009  David Lenaerts
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Author information:
 * David Lenaerts
 * url: http://www.derschmale.com
 * mail: david.lenaerts@gmail.com
 * 
 * NOTE: The textures used in this programme are not covered by the license. The BlastDoor set
 * is made by Florian Zender (http://www.florianzender.com/) and it is used with his kind permission.
 */

package
{
	import com.derschmale.stok3d.filters.PhongFilter;
	
	import flash.display.Bitmap;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.ui.Keyboard;
	
	/**
	 * Native FP10 3D Phong Shading demo
	 */
	
	[SWF(width="600", height="600", frameRate="30", backgroundColor="0x000000")]
	public class PhongExample extends Sprite
	{
		[Embed(source="/../exampleAssets/phong/2008_BlastDoor_TextureDiff_large.jpg")]
		private var Texture : Class;
		
		[Embed(source="/../exampleAssets/phong/2008_BlastDoor_TextureNormal_large.jpg")]
		private var NormalMap : Class;
		
		[Embed(source="/../exampleAssets/phong/2008_BlastDoor_TextureSpec_large.jpg")]
		private var SpecularMap : Class;
		
		private var _startX : Number;
		private var _startY : Number;
		
		private var _mouseDown : Boolean;
		
		private var _surface : Sprite;
		
		private var _specFilter : PhongFilter;	// an instance with specular map
		private var _normFilter : PhongFilter;	// an instance without specular map
		
		private var _filter : PhongFilter;		// a reference to either filter instance currently active
		
		private var _lightRotation : Number = 0;
		
		private var _glossCount : int = 5;
		
		public function PhongExample()
		{
			initView();
			initFilter();
			
			stage.addEventListener(MouseEvent.MOUSE_DOWN, handleMouseDown);
			stage.addEventListener(MouseEvent.MOUSE_UP, handleMouseUp);
			stage.addEventListener(KeyboardEvent.KEY_UP, handleKeyUp);
			addEventListener(Event.ENTER_FRAME, handleEnterFrame);
		}
		
		private function initView() : void
		{
			// init background
			var textField : TextField = new TextField();
			textField.textColor = 0xffffff;
			textField.multiline = true;
			textField.text = 	"Click & drag : Rotate surface\n" + 
								"+/- : Change gloss\n" + 
								"PgUp/PgDown : Change surface relief\n" + 
								"Space: Toggle specular map";
			textField.width = textField.textWidth + 10;
			textField.height = textField.textHeight + 10;
			textField.x = stage.stageWidth-textField.width;
			addChild(textField);
			// init rotatable surface, make sure registration point is in center
			var bmp : Bitmap = new Texture();
			bmp.smoothing = false;
			bmp.x = -bmp.width*.5;
			bmp.y = -bmp.height*.5;
			_surface = new Sprite();
			_surface.addChild(bmp);
			
			_surface.z = 300;
			
			// position and scale
			_surface.x = stage.stageWidth*.5;
			_surface.y = stage.stageHeight*.5;
			
			_surface.scaleY = 2;
			_surface.scaleX = 2;
			
			addChild(_surface);
		}
		
		private function handleKeyUp(event : KeyboardEvent) : void
		{
			switch(event.keyCode) {
				case 107:	// +
					_glossCount++;
					if (_glossCount > 10) _glossCount = 10;
					_normFilter.gloss = _specFilter.gloss = Math.pow(2, _glossCount);
					_surface.filters = [_filter];
					break;
				case 109:	// -
					_glossCount--;
					if (_glossCount < 0) _glossCount = 0;
					_normFilter.gloss = _specFilter.gloss = Math.pow(2, _glossCount);
					_surface.filters = [_filter];
					break;
				case Keyboard.PAGE_UP:
					_specFilter.normalMapStrength += 0.02;
					_normFilter.normalMapStrength += 0.02;
					if (_filter.normalMapStrength > 0.5) {
						_specFilter.normalMapStrength = .5;
						_normFilter.normalMapStrength = .5;
					}
					_surface.filters = [_filter];
					break;
				case Keyboard.PAGE_DOWN:
					_specFilter.normalMapStrength -= 0.02;
					_normFilter.normalMapStrength -= 0.02;
					if (_filter.normalMapStrength < 0.0) {
						_normFilter.normalMapStrength = 0.0;
						_specFilter.normalMapStrength = 0.0;
					}
					_surface.filters = [_filter];
					break;
				case Keyboard.SPACE:
					// switch active filter
					if (_filter == _specFilter) _filter = _normFilter;
					else _filter = _specFilter;
					break;
			}
		}
		
		/**
		 * Create the EnvMapFilter object and assign it to the surface
		 */
		private function initFilter() : void
		{
			_normFilter = new PhongFilter(1, 100, new NormalMap().bitmapData, 0.5, null);
			_specFilter = new PhongFilter(1, 100, new NormalMap().bitmapData, 0.5, new SpecularMap().bitmapData);
			_specFilter.ambientColor = _normFilter.ambientColor = 0x000015;
			_specFilter.specularColor = _normFilter.specularColor = 0xffff80;
			_filter = _specFilter;
			_filter.update(_surface);
			_surface.filters = [ _filter ];
		}
		
		/**
		 * Indicate rotation has started with the current mouse position as motion reference
		 */
		private function handleMouseDown(event : MouseEvent) : void
		{
			_mouseDown = true;
			_startX = mouseX;
			_startY = mouseY;
		}
		
		/**
		 * Indicate rotation has stopped
		 */
		private function handleMouseUp(event : MouseEvent) : void
		{
			_mouseDown = false;
		}
		
		/**
		 * Update filter and surface position
		 */
		private function handleEnterFrame(event : Event) : void
		{
			// move the light's position
			_lightRotation += .03;
			_filter.lightPosition.x = Math.sin(_lightRotation)*500;
			_filter.lightPosition.y = Math.sin(_lightRotation*2)*100;
			_filter.lightPosition.z = Math.cos(_lightRotation)*300-50;
			
			// rotate if mouse is down
			if (_mouseDown) {
		 		_surface.rotationY += (_startX-mouseX)*.01;
		 		_surface.rotationX += (_startY-mouseY)*.01;
		 	}
		 	
		 	// update the filter
		 	_filter.update(_surface);
		 	_surface.filters = [ _filter ];
		}
	}
}